#include "../include/server.h"
#include "../include/header.h"
#include "../include/database.h"
#include "../include/cJSON.h"
#include "../include/threadpool.h"

void handle_client_task(void *arg)
{
    int client_sock = *(int *)arg;
    free(arg);
    char buffer[BUFFER_SIZE] = {0};
    int valread = read(client_sock, buffer, BUFFER_SIZE);
    // {"action":"requtest", "username", "testuser", "password": "password123"}

    if (valread > 0)
    {
        printf("Received: %s\n", buffer);
        cJSON *json = cJSON_Parse(buffer);

        if (json)
        {
            cJSON *action = cJSON_GetObjectItem(json, "action");
            cJSON *username = cJSON_GetObjectItem(json, "username");
            cJSON *password = cJSON_GetObjectItem(json, "password");

            MYSQL *conn = db_connect();
            if (!conn)
            {
                send(client_sock, "Database connection failed", 26, 0);
                close(client_sock);
                return;
            }

            if (cJSON_IsString(action))
            {
                if (strcmp(action->valuestring, "register") == 0)
                {
                    int success = db_register_user(conn, username->valuestring, password->valuestring);
                    send(client_sock, success ? "Registration successful" : "Registration failed", 20, 0);
                }
                else if (strcmp(action->valuestring, "login") == 0)
                {
                    int success = db_login_user(conn, username->valuestring, password->valuestring);
                    send(client_sock, success ? "Login successful" : "Login failed", 15, 0);
                }
            }

            db_close(conn);
            cJSON_Delete(json);
        }
    }
    close(client_sock);
}

void start_server()
{
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == 0)
    {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(SERVER_PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
    {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server_fd, 5) < 0)
    {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }

    printf("Server is listening on port %d...\n", SERVER_PORT);

    threadpool_t *pool = threadpool_create(4, 10);
    if (!pool)
    {
        perror("Failed to create thread pool");
        exit(EXIT_FAILURE);
    }

    while (1)
    {
        new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen);
        if (new_socket < 0)
        {
            perror("Accept failed");
            continue;
        }

        int *client_sock = malloc(sizeof(int));
        *client_sock = new_socket;
        threadpool_add(pool, handle_client_task, (void *)client_sock);
    }
    threadpool_destroy(pool);
    close(server_fd);
}

int main(int argc, char const *argv[])
{
    printf("Starting server...\n");
    start_server();
    return 0;
}
